package fun.codedesign.yinxue.json.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.yinxue.swing.core.util.LogUtil;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * TODO 自己实现Json的解析规则
 */
public class JacksonService implements JsonService {

    ObjectMapper mapper = new ObjectMapper();

    @Override
    public String jsonPretty(String json) throws JsonProcessingException {
//        JSONObject object = JSONObject.parseObject(json);
//        String pretty = JSON.toJSONString(object, SerializerFeature.PrettyFormat,SerializerFeature.WriteSlashAsSpecial, SerializerFeature.WriteMapNullValue,
//                SerializerFeature.WriteDateUseDateFormat);
        Object obj = mapper.readValue(json, Object.class);
        String pretty = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        System.out.println(pretty);
        return pretty;
    }

    @Override
    public String jsonOneLine(String json) {
        return json.replaceAll("\\s", "");
    }

    @Override
    public String generateJavaType(String json) throws Exception {
        Map<String, Object> typeMap = buildTypeMap(json);
        String returnJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(typeMap);
        return returnJson;
    }

    private Map<String, Object> buildTypeMap(String json) throws Exception {
        Map<String, Object> itemMap = mapper.readValue(json, Map.class);
        Map<String, Object> typeMap = iterFieldsClassType(itemMap);
        return typeMap;
    }

    @Override
    public String generateJavaCode(String json) throws Exception {
        // 遍历出类型，然后构造pojo
        Map<String, Object> typeMap = buildTypeMap(json);
        // 分块代码
        LinkedList<String> codeBlockList = new LinkedList<>();
        // 迭代深度
        AtomicInteger deep = new AtomicInteger(0);

        codeBlockList.add("@Data\npublic class Dto implements Serializable {\n");
        iterToBlocks(typeMap, codeBlockList, deep);
        codeBlockList.add("}");

        // 检查 codeList 增加一些导入包
        Set<String> importList = new HashSet<>();
        checkImport(codeBlockList, importList);
        // import line
        StringBuilder builder = new StringBuilder();
        importList.forEach(builder::append);
        builder.append("\n");
        // code line
        codeBlockList.forEach(builder::append);
        return builder.toString();
    }

    @Override
    public String generateGroovyCode(String json) throws Exception {
        // 遍历出类型，然后构造pojo
        Map<String, Object> typeMap = buildTypeMap(json);
        // 分块代码
        LinkedList<String> codeBlockList = new LinkedList<>();
        // 迭代深度
        AtomicInteger deep = new AtomicInteger(0);

        codeBlockList.add("class Dto {\n");
        // TODO 把private去掉，public去掉 与java的区别
        iterToBlocks2(typeMap, codeBlockList, deep);
        codeBlockList.add("}");

        // 检查 codeList 增加一些导入包
        Set<String> importList = new HashSet<>();
        checkImport(codeBlockList, importList);
        // import line
        StringBuilder builder = new StringBuilder();
        importList.forEach(builder::append);
        builder.append("\n");
        // code line
        codeBlockList.forEach(builder::append);
        return builder.toString();
    }

    private void checkImport(LinkedList<String> codeBlockList, Set<String> importList) {
        codeBlockList.forEach(block -> {
            if (block.contains("List<")) {
                importList.add("import java.util.List;\n");
            }

            if (block.contains("@Data")) {
                importList.add("import lombok.Data;\n");
            }

            if (block.contains("Serializable")) {
                importList.add("import java.io.Serializable;\n");
            }
            // 某些厂商的返回参数为 大写或者有_下划线，就需要原样序列化返回，增加原样注解
            if (block.contains("@JsonProperty")) {
                importList.add("import com.fasterxml.jackson.annotation.JsonProperty;\n");

            }
        });
    }

    private void iterToBlocks2(Map<String, Object> typeMap, List<String> codeBlockList, AtomicInteger deep) {
        int deepCount = deep.incrementAndGet();
        typeMap.entrySet().forEach(entry -> {
            String propertyName = entry.getKey();
            String annotationLine = "";
            if (propertyName.contains("_")) {
                annotationLine = "@JsonProperty(\"" + propertyName + "\")\n";
                // 驼峰转换
                propertyName = toCamelCase(propertyName);
            }
            // default是java限制字段，改写为 defaultValue
            if (propertyName.equals("default")) {
                annotationLine = "@JsonProperty(\"" + propertyName + "\")\n";
                propertyName = "defaultValue";
            }
            // 如果字段包含 @，java禁用，则同上面一样转换下
            if (propertyName.contains("@")) {
                annotationLine = "@JsonProperty(\"" + propertyName + "\")\n";
                propertyName = propertyName.replaceAll("@", "");
            }

            Object propertyInfo = entry.getValue();
            if (propertyInfo instanceof Map) {
                // 1. 一个变量
                StringBuilder builder = newBuilderByDeep(deepCount);
                // 首字母大写
                String defaultClassName = firstUpper(propertyName);
                appendAnnotationLine(builder, deepCount, annotationLine);
//                builder.append("private ");
                builder.append(defaultClassName).append(" ").append(propertyName).append(";\n");
                codeBlockList.add(builder.toString());

                // 2.一个内部类对象 TODO与下同，可抽取，注意map对象的名称仅是首字母大写
                String defineInnerClassName = firstUpper(propertyName);
                List<String> innerClassCodeBlock = new ArrayList<>();
                // 用1好像有点问题？， 使用当前deep
                StringBuilder innerClassBuilder = newBuilderByDeep(deepCount);
//                innerClassBuilder.append("@Data\n");
//                appendDeepWhite(innerClassBuilder, deepCount);
                // 去除public
                innerClassBuilder.append("static class ").append(defineInnerClassName).append(" {\n");
                // 递归：变量默认为2的深度? 有问题，使用当前deep
                iterToBlocks2((Map) propertyInfo, innerClassCodeBlock, deep);
                innerClassCodeBlock.forEach(innerClassBuilder::append);
                // for (int i = 0; i < deepCount-1; i++) {
                // innerClassBuilder.append(" ");
                // }
                appendDeepWhite(innerClassBuilder, deepCount);
                innerClassBuilder.append("}\n");
                codeBlockList.add(innerClassBuilder.toString());
            } else if (propertyInfo instanceof List) {
                // NULL? TODO
                List<?> propertyInfoList = (List<?>) propertyInfo;
                // 构建对象或者List<String>
                // 1. 一个List变量，
                // ?2. 根据实际需要是否内部类对象
                if (propertyInfoList.isEmpty()) {
                    StringBuilder builder = newBuilderByDeep(deepCount);
                    // 空的情况默认用 List<String> xxx;
                    appendAnnotationLine(builder, deepCount, annotationLine);
//                    builder.append("private ");
                    builder.append("List<String> ").append(propertyName).append(";\n");
                    codeBlockList.add(builder.toString());
                } else if (propertyInfoList.get(0) instanceof Class) {
                    // 不空的情况，如果value为class则用 List<$ClassName> xxx;
                    StringBuilder buidler = newBuilderByDeep(deepCount);
                    buidler.append("List<").append(((Class) propertyInfoList.get(0)).getSimpleName()).append("> ")
                            .append(propertyName).append(";\n");
                    codeBlockList.add(buidler.toString());
                } else if (propertyInfoList.get(0) instanceof Map) {
                    // map的情况，className为在原有的变量上加一个Item，以保险起见，生成后可自行修改
                    StringBuilder builder = newBuilderByDeep(deepCount);
                    String defineInnerClassName = firstUpper(propertyName) + "Item";
                    appendAnnotationLine(builder, deepCount, annotationLine);
//                    builder.append("private ");
                    builder.append("List<").append(defineInnerClassName).append("> ").append(propertyName)
                            .append(";\n");
                    codeBlockList.add(builder.toString());

                    // 内部类统一用1的深度, 用1的深度似乎有缩进不对的问题 TODO
                    List<String> innerClassCodeBlock = new ArrayList<>();
                    StringBuilder innderClassBuilder = newBuilderByDeep(deepCount);
//                    innderClassBuilder.append("@Data\n");
//                    appendDeepWhite(innderClassBuilder, deepCount);
                    innderClassBuilder.append("static class ").append(defineInnerClassName).append(" {\n");
                    // 递归：变量默认为2的深度，用2的深度似乎也有问题
                    iterToBlocks2((Map) propertyInfoList.get(0), innerClassCodeBlock, deep);
                    innerClassCodeBlock.forEach(innderClassBuilder::append);
                    // for (int i = 0; i < deepCount-1; i++) {
                    // innderClassBuilder.append(" ");
                    // }
                    appendDeepWhite(innderClassBuilder, deepCount);
                    innderClassBuilder.append("}\n");
                    codeBlockList.add(innderClassBuilder.toString());
                } else {
                    LogUtil.error("propertyInfoList [{}] no classType info", propertyName, deep);
                    ;
                }
                // 普通类直接组装代码
            } else {
                StringBuilder builder = newBuilderByDeep(deepCount);
                appendAnnotationLine(builder, deepCount, annotationLine);
//                builder.append("private ");
                builder.append(((Class) propertyInfo).getSimpleName())
                        .append(" ")
                        .append(propertyName)
                        .append(";\n");
                codeBlockList.add(builder.toString());
            }
        });
        deep.decrementAndGet();
    }

    private void iterToBlocks(Map<String, Object> typeMap, List<String> codeBlockList, AtomicInteger deep) {
        int deepCount = deep.incrementAndGet();
        typeMap.entrySet().forEach(entry -> {
            String propertyName = entry.getKey();
            String annotationLine = "";
            if (propertyName.contains("_")) {
                annotationLine = "@JsonProperty(\"" + propertyName + "\")\n";
                // 驼峰转换
                propertyName = toCamelCase(propertyName);
            }
            // default是java限制字段，改写为 defaultValue
            if (propertyName.equals("default")) {
                annotationLine = "@JsonProperty(\"" + propertyName + "\")\n";
                propertyName = "defaultValue";
            }
            // 如果字段包含 @，java禁用，则同上面一样转换下
            if (propertyName.contains("@")) {
                annotationLine = "@JsonProperty(\"" + propertyName + "\")\n";
                propertyName = propertyName.replaceAll("@", "");
            }

            Object propertyInfo = entry.getValue();
            if (propertyInfo instanceof Map) {
                // 1. 一个变量
                StringBuilder builder = newBuilderByDeep(deepCount);
                // 首字母大写
                String defaultClassName = firstUpper(propertyName);
                appendAnnotationLine(builder, deepCount, annotationLine);
                builder.append("private ");
                builder.append(defaultClassName).append(" ").append(propertyName).append(";\n");
                codeBlockList.add(builder.toString());

                // 2.一个内部类对象 TODO与下同，可抽取，注意map对象的名称仅是首字母大写
                String defineInnerClassName = firstUpper(propertyName);
                List<String> innerClassCodeBlock = new ArrayList<>();
                // 用1好像有点问题？， 使用当前deep
                StringBuilder innerClassBuilder = newBuilderByDeep(deepCount);
                innerClassBuilder.append("@Data\n");
                appendDeepWhite(innerClassBuilder, deepCount);
                innerClassBuilder.append("public static class ").append(defineInnerClassName).append(" {\n");
                // 递归：变量默认为2的深度? 有问题，使用当前deep
                iterToBlocks((Map) propertyInfo, innerClassCodeBlock, deep);
                innerClassCodeBlock.forEach(innerClassBuilder::append);
                // for (int i = 0; i < deepCount-1; i++) {
                // innerClassBuilder.append(" ");
                // }
                appendDeepWhite(innerClassBuilder, deepCount);
                innerClassBuilder.append("}\n");
                codeBlockList.add(innerClassBuilder.toString());
            } else if (propertyInfo instanceof List) {
                // NULL? TODO
                List<?> propertyInfoList = (List<?>) propertyInfo;
                // 构建对象或者List<String>
                // 1. 一个List变量，
                // ?2. 根据实际需要是否内部类对象
                if (propertyInfoList.isEmpty()) {
                    StringBuilder builder = newBuilderByDeep(deepCount);
                    // 空的情况默认用 List<String> xxx;
                    appendAnnotationLine(builder, deepCount, annotationLine);
                    builder.append("private ");
                    builder.append("List<String> ").append(propertyName).append(";\n");
                    codeBlockList.add(builder.toString());
                } else if (propertyInfoList.get(0) instanceof Class) {
                    // 不空的情况，如果value为class则用 List<$ClassName> xxx;
                    StringBuilder buidler = newBuilderByDeep(deepCount);
                    buidler.append("List<").append(((Class) propertyInfoList.get(0)).getSimpleName()).append("> ")
                            .append(propertyName).append(";\n");
                    codeBlockList.add(buidler.toString());
                } else if (propertyInfoList.get(0) instanceof Map) {
                    // map的情况，className为在原有的变量上加一个Item，以保险起见，生成后可自行修改
                    StringBuilder builder = newBuilderByDeep(deepCount);
                    String defineInnerClassName = firstUpper(propertyName) + "Item";
                    appendAnnotationLine(builder, deepCount, annotationLine);
                    builder.append("private ");
                    builder.append("List<").append(defineInnerClassName).append("> ").append(propertyName)
                            .append(";\n");
                    codeBlockList.add(builder.toString());

                    // 内部类统一用1的深度, 用1的深度似乎有缩进不对的问题 TODO
                    List<String> innerClassCodeBlock = new ArrayList<>();
                    StringBuilder innderClassBuilder = newBuilderByDeep(deepCount);
                    innderClassBuilder.append("@Data\n");
                    appendDeepWhite(innderClassBuilder, deepCount);
                    innderClassBuilder.append("public static class ").append(defineInnerClassName).append(" {\n");
                    // 递归：变量默认为2的深度，用2的深度似乎也有问题
                    iterToBlocks((Map) propertyInfoList.get(0), innerClassCodeBlock, deep);
                    innerClassCodeBlock.forEach(innderClassBuilder::append);
                    // for (int i = 0; i < deepCount-1; i++) {
                    // innderClassBuilder.append(" ");
                    // }
                    appendDeepWhite(innderClassBuilder, deepCount);
                    innderClassBuilder.append("}\n");
                    codeBlockList.add(innderClassBuilder.toString());
                } else {
                    LogUtil.error("propertyInfoList [{}] no classType info", propertyName, deep);
                    ;
                }
                // 普通类直接组装代码
            } else {
                StringBuilder builder = newBuilderByDeep(deepCount);
                appendAnnotationLine(builder, deepCount, annotationLine);
                builder.append("private ");
                builder.append(((Class) propertyInfo).getSimpleName())
                        .append(" ")
                        .append(propertyName)
                        .append(";\n");
                codeBlockList.add(builder.toString());
            }
        });
        deep.decrementAndGet();
    }

    private String firstUpper(String propertyName) {
        return propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
    }

    /**
     * 驼峰处理，以下划线后一位修改为大写为标准
     *
     * @param sqlFieldList
     * @return
     */
    private String toCamelCase(final String sqlFieldList) {
        // 1.小写处理
        String lowerStr = sqlFieldList.toLowerCase();
        StringBuilder builder = new StringBuilder(lowerStr);
        Pattern p = Pattern.compile("_");
        Matcher m = p.matcher(builder);
        int index = 0;
        while (m.find()) {
            // end = 匹配组0的最后一个字符的索引+1
            index = m.end();
            // 2.获得下划线后的首字母，并作大写处理
            char c = Character.toUpperCase(builder.charAt(index));
            builder.setCharAt(index, c);
        }
        // 3.替换下划线为""
        return builder.toString().replaceAll("_", "");
    }

    private StringBuilder newBuilderByDeep(int deep) {
        StringBuilder builder = new StringBuilder();
        appendDeepWhite(builder, deep);
        return builder;
    }

    private void appendAnnotationLine(StringBuilder builder, int deep, String annotationLine) {
        // 空的情况不需要拼接缩进
        if (!annotationLine.equalsIgnoreCase("")) {
            builder.append(annotationLine);
            appendDeepWhite(builder, deep);
        }
    }

    private void appendDeepWhite(StringBuilder builder, int deep) {
        for (int index = 0; index < deep; index++) {
            builder.append("    ");
        }
    }

    Map<String, Object> iterFieldsClassType(Map<String, Object> map) {
        Map<String, Object> target = new HashMap<>();
        map.entrySet().forEach(entry -> {
            String key = entry.getKey();
            Object value = entry.getValue();
            // if (value instanceof String) {
            // target.put(key, String.class);
            // }
            // if (value instanceof Integer) {
            // target.put(key, Number.class);
            // }
            if (key != null) {
                if (value == null) {
                    target.put(key, String.class);
                } else if (value instanceof Number) {
                    // 用Long避免 解析出来的Integer值出现溢出的情况，例如示例中的id、last_order_id字段: https://shopify.dev/api/admin-rest/2022-10/resources/customer#get-customers-search?query=email:bob.norman@mail.example.com
                    target.put(key, Long.class);
                } else if (value instanceof Map) {
                    target.put(key, iterFieldsClassType((Map) value));
                } else if (value instanceof List) {
                    target.put(key, iterList((List) value));
                } else {
                    // object有点问题 todo
                    target.put(key, value == null ? String.class : value.getClass());
                }
            }
        });
        return target;
    }

    private List iterList(List value) {
        // 如果是空对象则返回空的 targetList

        // 如果是对象就只放一个，如果是 普通类就List直接放一个类即可。
        List<Object> targetList = new ArrayList<>();

        if (value == null || value.isEmpty()) {
            return targetList;
        }

        for (Object item : value) {
            if (item instanceof Map) {
                targetList.add(iterFieldsClassType((Map) item));
                break;
                // 普通类
            } else {
                targetList.add(item.getClass());
                break;
            }
        }
        return targetList;
    }

    public String append(Map<String, Object> iterMap) {
        return null;
    }

}
